# coding:utf-8
import time
import json
from random import sample, randint
from math import ceil
from datetime import datetime, timedelta, date

from sqlalchemy import and_, or_

from common.producer import Producer
from .models import model_factory, DemandCate, DemandColor, DemandType, \
    FollowType, ParticStatus, DemandStatus
from .utils import DB, redis_client
from .constant import WATERING_USER_IDS, WATERING_INDEX, \
    SECOND_WATERING_INDEX, OTHER_WATERING_INDEX, BID_USER_COUNT, \
    COMMON_API_QUEUE
from .schedule.robot_task import auto_offer_task
from common.log import Log


def start_robot_task(demand, session=None):
    """
    created by chenhj at 02/02/2018

    """
    demand_id = demand.id
    published_count = demand.published_count
    print('start robot, demand_id: {}'.format(demand_id))
    expect_bid_point, user_ids = get_watering_info(demand, session)

    if expect_bid_point and user_ids:
        now = datetime.utcnow()
        delay = randint(30, 60)
        auto_offer_task.apply_async(
            (demand_id, published_count, user_ids, expect_bid_point),
            eta=now + timedelta(seconds=delay),
            expires=now + timedelta(seconds=10 + delay)
        )


def get_watering_user_ids(session):
    """
    created by chenhj at 02/02/2018
    获取浇水用户id列表
    """
    user_ids = redis_client.get(WATERING_USER_IDS)
    if not user_ids:
        watering_users = session.query(model_factory.user).filter(
            model_factory.user.mobile.startswith('3000000'),
            model_factory.user.is_virt == 1
        ).all()
        user_ids = json.dumps([x.id for x in watering_users])
        redis_client.set(WATERING_USER_IDS, user_ids)
    return json.loads(user_ids)


def get_expected_bid_point(demand, area):
    """
    created by chenhj at 2018/4/25
    计算期望成交价
    """
    def get_size_bid_point():
        """
        created by chenhj at 01/02/2018

        """
        size = demand.size
        if demand.cate == DemandCate.INSTALL.value:
            if 0 <= size < 3:
                bid_point = 10
            elif 3 <= size < 10:
                bid_point = 20
            elif 10 <= size < 15:
                bid_point = 60
            elif 15 <= size < 30:
                bid_point = 120
            else:
                bid_point = 300
            return bid_point * 0.5
        if demand.cate == DemandCate.RENT.value:
            if 0 <= size < 10:
                bid_point = 5
            elif 10 <= size < 25:
                bid_point = 15
            else:
                bid_point = 40
            return bid_point * 0.6

    def get_color_bid_point():
        """
        created by chenhj at 01/02/2018

        """
        if demand.cate == DemandCate.INSTALL.value:
            if demand.color == DemandColor.FULL_COLOR.value:
                bid_point = 150
            else:
                bid_point = 50
        else:
            bid_point = 0
        return bid_point * 0.2

    def get_span_bid_point():
        """
        created by chenhj at 01/02/2018

        """
        span = demand.span.replace('P', '').replace('p', '')
        if not span:
            return 0
        try:
            span = float(span)
        except:
            return 0
        if demand.cate == DemandCate.INSTALL.value:
            if 0.0 <= span < 3.0:
                bid_point = 320
            elif 3.0 <= span < 5.0:
                bid_point = 150
            elif 5.0 <= span < 10.0:
                bid_point = 80
            else:
                bid_point = 40
            return bid_point * 0.3
        if demand.cate == DemandCate.RENT.value:
            if 0.0 <= span < 3.0:
                bid_point = 50
            elif 3.0 <= span < 10.0:
                bid_point = 30
            else:
                bid_point = 10
            return bid_point * 0.4

    def get_type_factor():
        """
        created by chenhj at 2018/4/25

        """
        factor_dic = {
            DemandType.DOOR_SCREEN.value: 0.6,
            DemandType.INFO_BULLETIN_SCREEN.value: 0.8,
            DemandType.INDOOR_SCREEN.value: 1,
            DemandType.STAGE_SCREEN.value: 1,
            DemandType.OUTDOOR_AD_SCREEN.value: 1,
            DemandType.OTHER_SCREEN.value: 0.8
        }
        return factor_dic.get(demand.type, 1)

    if demand.cate not in (DemandCate.INSTALL.value, DemandCate.RENT.value):
        return 0

    init_bid_point = int(
        (get_size_bid_point() + get_color_bid_point() + get_span_bid_point())
        * float(area.water_factor)
        * float(get_type_factor())
    )

    if demand.published_count == 1:
        watering_index_key = WATERING_INDEX
    elif demand.published_count == 2:
        watering_index_key = SECOND_WATERING_INDEX
    else:
        watering_index_key = OTHER_WATERING_INDEX
    watering_index = float(redis_client.get(watering_index_key) or '1.0')
    return min(
        int(ceil(init_bid_point / 10) * 10 * watering_index + (demand.id % 10)), 200
    )


def get_watering_info(demand, session=None):
    """
    created by chenhj at 01/02/2018
    获取自动浇水相关参数
    @return: (期望成交价, 出场人id列表)
    """
    if demand.cate not in (DemandCate.INSTALL.value, DemandCate.RENT.value):
        return None, None

    with DB(session) as session:
        watering_user_ids = get_watering_user_ids(session)
        if not watering_user_ids:
            return None, None
        area = model_factory.area.get_by_id(session, demand.area_id)
        if not area:
            return None, None
        expect_bid_point = get_expected_bid_point(demand, area)

        if expect_bid_point == 0:
            return 0, []
        if 100 <= expect_bid_point <= 200:
            return expect_bid_point, sample(watering_user_ids, 7)
        elif 50 <= expect_bid_point < 100:
            return expect_bid_point, sample(watering_user_ids, 5)
        return expect_bid_point, sample(watering_user_ids, 4)


def demand_winner_count(demand_id, session=None):
    """
    create by ld_wu 2018-07-03
    项目抢单成功的总人数（不包含取消跟进的及机器人）
    :return:
    """
    with DB(session) as session:
        bid_user_count = session.query(model_factory.partic).filter(
            model_factory.partic.demand_id == demand_id,
            model_factory.partic.follow_type != FollowType.GIVE_UP.value,
            model_factory.partic.status.in_([
                ParticStatus.NOT_CONTACT.value,
                ParticStatus.BALANCE_NOT_ENOUGH.value,
                ParticStatus.SUCCEED.value
            ]),
            model_factory.partic.is_robot.__eq__(False),
            model_factory.partic.is_training.__eq__(False)
        ).count()
        return bid_user_count


def demand_bid_count(demand_id, published_count, session=None):
    """
    中标人数（本轮中标加非本轮成功的）
    派单环节，获得虚拟号就算中标
    优先抢单环节，出价成功就算中标
    竞价抢单环节，竞价成功就算中标
    :return:
    """
    with DB(session) as session:
        return session.query(
            model_factory.partic
        ).filter(
            model_factory.partic.demand_id == demand_id,
            or_(
                and_(
                    model_factory.partic.status == ParticStatus.SUCCEED.value,
                    model_factory.partic.published_count != published_count,
                    model_factory.partic.follow_type != FollowType.GIVE_UP.value,
                    model_factory.partic.is_robot.__eq__(False)
                ),
                and_(
                    model_factory.partic.status.in_([
                        ParticStatus.NOT_CONTACT.value,
                        ParticStatus.BALANCE_NOT_ENOUGH.value,
                        ParticStatus.SUCCEED.value,
                        ParticStatus.TIMEOUT_NOT_CONTACT.value
                    ]),
                    model_factory.partic.published_count == published_count
                )
            ),
            model_factory.partic.is_training.__eq__(False)
        ).count()


def demand_complete(demand):
    if demand.status not in (DemandStatus.INVALID.value, DemandStatus.DONE.value):
        demand.status = DemandStatus.COMPETE_DONE.value
        

def demand_to_complete(session, demand):
    """
    create by ld_wu 2018-08-01
    中标人数达标时修改项目状态为抢单结束
    :param session: 
    :param demand: 
    :return: 
    """
    had_overflow = (
        demand_bid_count(
            demand.id,
            demand.published_count,
            session) >= BID_USER_COUNT
    )
    if had_overflow:
        demand_complete(demand)
    return had_overflow


def gen_renewable_demand(session, demand):
    """
    create by ld_wu 2018-08-01
    订单进入回收站
    :return:
    """
    Log.info('renewable_demand:{}'.format(demand.id))
    # 非抢单结束，不进入回收站
    if demand.status != DemandStatus.COMPETE_DONE.value:
        return
    # 维修单不进二发
    if demand.cate == DemandCate.MAINTAIN.value:
        return
    if demand.published_count != 1:
        return
    is_locked = model_factory.partic.get_by_args(
        session,
        status=ParticStatus.SUCCEED.value,
        demand_id=demand.id,
        deleted_at=0,
        follow_type=FollowType.LOCKED.value
    )
    # 锁定订单不进入回收站
    if is_locked:
        return
    winner_count = demand_winner_count(demand.id, session)
    if winner_count < BID_USER_COUNT:
        Log.info('in to trash:{}'.format(demand.id))
        renewable_demand = model_factory.renewable_demands.get_by_args(
            session,
            demand_id=demand.id
        )
        if not renewable_demand:
            model_factory.renewable_demands.create(
                session,
                demand_id=demand.id,
                recovery_at=int(time.time()),
                recovery_date=date.today(),
                operator_id=0,
                operator_name='',
                operated_at=0,
                operated_status=0,
                recovery_success_count=0
            )
            # 写入订单回收统计
            common_producer = Producer(COMMON_API_QUEUE)
            common_producer.send(
                json.dumps(
                    dict(
                        backend='renewable_stat',
                        func='renewable_stat',
                        kwargs=dict(
                            demand_id=demand.id
                        )
                    )
                )
            )